
#include "RMathHelper.h"

using namespace Riccsson;
using namespace Riccsson::Xna::Framework;

const float MathHelper::E = (float)System::Math::E;
const float MathHelper::Log10E = 0.4342945f;
const float MathHelper::Log2E = 1.442695f;
const float MathHelper::Pi = (float)System::Math::PI;
const float MathHelper::PiOver2 = (float)(System::Math::PI / 2.0);
const float MathHelper::PiOver4 = (float)(System::Math::PI / 4.0);
const float MathHelper::TwoPi = (float)(System::Math::PI * 2.0);

MathHelper::MathHelper() {}; // Make this class static.

float MathHelper::Barycentric(float value1, float value2, float value3, float amount1, float amount2)
{
	return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2;
}
float MathHelper::CatmullRom(float value1, float value2, float value3, float value4, float amount)
{
	// Using formula from http://www.mvps.org/directx/articles/catmull/
	// Internally using doubles not to lose precission
	double amountSquared = amount * amount;
	double amountCubed = amountSquared * amount;
	return (float)(0.5 * (2.0 * value2 +
		(value3 - value1) * amount +
		(2.0 * value1 - 5.0 * value2 + 4.0 * value3 - value4) * amountSquared +
		(3.0 * value2 - value1 - 3.0 * value3 + value4) * amountCubed));
}
float MathHelper::ClampF(float value, float min, float max)
{
	// First we check to see if we're greater than the max
	value = (value > max) ? max : value;

	// Then we check to see if we're less than the min.
	value = (value < min) ? min : value;

	// There's no check to see if min > max.
	return value;
}
int MathHelper::Clamp(int value, int min, int max)
{ 
	value = (value > max) ? max : value; 
	value = (value < min) ? min : value; 
	return value;
}
float MathHelper::Distance(float value1, float value2)
{
	return Riccsson::System::Math::Abs(value1 - value2);
}
float MathHelper::Hermite(float value1, float tangent1, float value2, float tangent2, float amount)
{
	// All transformed to double not to lose precission
	// Otherwise, for high numbers of param:amount the result is NaN instead of Infinity
	double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result;
	double sCubed = s * s * s;
	double sSquared = s * s;

	if (amount == 0.0f)
		result = value1;
	else if (amount == 1.0f)
		result = value2;
	else
		result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed +
			(3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared +
			t1 * s +
			v1;
	return (float)result;
}
float MathHelper::Lerp(float value1, float value2, float amount)
{
	return value1 + (value2 - value1) * amount;
}
float MathHelper::Max(float value1, float value2)
{
	return Riccsson::System::Math::Max(value1, value2);
}
float MathHelper::Min(float value1, float value2)
{
	return Riccsson::System::Math::Min(value1, value2);
}
float MathHelper::SmoothStep(float value1, float value2, float amount)
{
	// It is expected that 0 < amount < 1
	// If amount < 0, return value1
	// If amount > 1, return value2
#if(USE_FARSEER)
	float result = SilverSpriteMathHelper.Clamp(amount, 0f, 1f);
	result = SilverSpriteMathHelper.Hermite(value1, 0f, value2, 0f, result);
#else
	float result = MathHelper::ClampF(amount, 0.0f, 1.0f);
	result = MathHelper::Hermite(value1, 0.0f, value2, 0.0f, result);
#endif
	return result;
}
float MathHelper::ToDegrees(float radians)
{ 
	return (float)(radians * 57.295779513082320876798154814105);
}
float MathHelper::ToRadians(float degrees)
{ 
	return (float)(degrees * 0.017453292519943295769236907684886);
}
float MathHelper::WrapAngle(float angle)
{
	angle = (float)Riccsson::System::Math::IEEERemainder((double)angle, 6.2831854820251465);
	if (angle <= -3.14159274f)
	{
		angle += 6.28318548f;
	}
	else
	{
		if (angle > 3.14159274f)
		{
			angle -= 6.28318548f;
		}
	}
	return angle;
}
bool MathHelper::IsPowerOfTwo(int value)
{
		return (value > 0) && ((value & (value - 1)) == 0);
}